using System;
using System.IO;
using Mono.Cecil;
using brainfucker;

namespace consoleCompiler
{
	class MainClass
	{
		public static void Main(string[] args)
		{
			if(args.Length == 0) {
			    NeedSourceFile();
			} else {
			    string source = "";
			    string output = "";
			    bool ignore = true;
			    bool endOfArgs = true;
			    bool interpret = false;
			    bool embed = false;
			    bool intArray = false;
			    for(int i = 0; i < args.Length; i++) {
			        switch(args[i]) {
			        case "--help":
			            Help();
			            return;
			        case "--version":
			            Version();
			            return;
			        case "--explicitComments":
			            ignore = false;
			            break;
			        case "--noEOF":
			            endOfArgs = false;
			            break;
			        case "--file":
			            source = args[++i];
			            break;
			        case "--output":
			            output = args[++i];
			            break;
			        case "--interpret":
			            interpret = true;
			            break;
			        case "--embedInterpreter":
			            embed = true;
			            break;
			        case "--intArray":
			            intArray = true;
			            break;
			        default:
			            if(args[i].StartsWith("--")) {
			                Help();
			                return;
			            } else {
			                if(source == "") {
			                    source = args[i];
			                } else if(output == "") {
			                    output = args[i];
			                } else {
			                    Help();
			                    return;
			                }
			            }
			            break;
			        }
			    }
			    if(source == "") {
			        NeedSourceFile();
			        return;
			    }
			    if(output == "") {
			        try {
			            output = Path.ChangeExtension(source, ".exe");
			        } catch {
			            output = source + ".exe";
			        }
			    } else {
    			    if(!output.EndsWith(".exe")) {
    	                output = output + ".exe";
    	            }
	            }
			    if(!File.Exists(source)) {
   		            Console.WriteLine("You must specify a valid source file");
   		        } else {
       		        if(interpret) {
       		            int size, offset;
       		            string sourceCode = File.ReadAllText(source);
       		            Interpreter.Analyze(sourceCode, out size, out offset);
       		            Interpreter interpreter = new Interpreter(size, offset);
       		            interpreter.Interpret(sourceCode);
       		        } else {
           		        try {
           		            string sourceCode = File.ReadAllText(source);
           		            try {
           		                string path = Path.GetFileNameWithoutExtension(source);
           		                AssemblyDefinition def = 
           		                    Compiler.Compile(path, sourceCode, ignore, intArray, endOfArgs, embed);
           		                AssemblyFactory.SaveAssembly(def, output);
           		                Console.WriteLine("Compiled succesfully to " + output);
           		            } catch (CompilerException e) {
           		                Console.WriteLine("Failed to compile: " + e.Message);
           		            }
           		        } catch(IOException e) {
           		            Console.WriteLine("Failed to open the source file: " + e.Message);
           		        }
       		        }
   		        }
			}
		}
		
		private static void NeedSourceFile()
		{
		    Console.WriteLine("You must specify a source file. See --help for more info.");
		}
		
		private static void Help()
		{
		     string name = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
		     name = Path.GetFileName(name);
		    
		    Console.WriteLine(name + @" [--file] sourceFile [[--output] outputFile]
  --interpret <file>    Will interpret the source file rather than compile it.
  
  --file <file>         Specify the source file to compile.
  
  --output <file>       Specify the output assembly name.
  
  --embedInterpreter    If set, the compiled assembly will include the source
                        code and an interpreter. Execution will be slower.
  
  --intArray            If set, the array will be of 32-bit integers rather than
                        8-bit bytes.
                        
  --noEOF               If set, no end-of-file value will follow argument input.
  
  --explicitComments    If set, the compiler will enforece comment demarcation.
                        Use this if you have code commented out. Does not work
                        with --interpret or --embedInterpreter.
                        
  --help                Display this information.
  
  --version             Display the compiler version.");
		}
		
		private static void Version()
		{
		    Console.WriteLine("brainfucker version: " + Compiler.Version);
		}
	}
}